package cc.verywell.pureblock.util.sign;

import java.nio.ByteBuffer;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.SignatureException;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.ShortBufferException;

import cc.verywell.pureblock.log.Pblog;
import cc.verywell.pureblock.util.SignServer;


/**
* 
* see https://docs.oracle.com/javase/7/docs/technotes/guides/security/StandardNames.html#KeyPairGenerator
* 
* @author TanYaqiu 
* @address flat 601
* @date 2019年2月25日 上午12:07:17
*/
public class EcServer implements SignServer {
	static String ENCRYPT_NAME_GEN = "EC" ;
	static String ENCRYPT_NAME = "ECIES" ;
	static String SIGN_NAME = "SHA256withECDSA" ;

	private byte[] pk;
	private PrivateKey sk;
	final protected Cipher encode,decode;
	final protected Signature signature;
	
	public EcServer() {
        this(genKey());
	}
	private EcServer(KeyPair kp) {
		this(kp.getPublic().getEncoded(),kp.getPrivate().getEncoded());
	}
	public EcServer(byte[] publicBytes,byte[] privateBytes) {
		this.pk = publicBytes;
		Cipher cipher;
        try {
			PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(privateBytes);
			KeyFactory keyFactory = KeyFactory.getInstance(ENCRYPT_NAME_GEN);
			PrivateKey privateKey = this.sk = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
			cipher = encode = Cipher.getInstance(ENCRYPT_NAME);
			cipher.init(Cipher.ENCRYPT_MODE, privateKey);
			cipher = decode = Cipher.getInstance(ENCRYPT_NAME);
			cipher.init(Cipher.DECRYPT_MODE, privateKey);
			signature = Signature.getInstance(SIGN_NAME);
			signature.initSign(privateKey);
		} catch (InvalidKeyException | NoSuchAlgorithmException | InvalidKeySpecException | NoSuchPaddingException e) {
			if(Pblog.INIT)Pblog.INIT(e);
			throw new RuntimeException(e);
		}
		
	}
	/**
	 * 
	 * @return RSA 密码
	 */
	private static KeyPair genKey() {
		
        KeyPairGenerator keyPairGenerator;
		try {
			keyPairGenerator = KeyPairGenerator.getInstance(ENCRYPT_NAME_GEN);
		} catch (NoSuchAlgorithmException e) {
			if(Pblog.INIT)Pblog.INIT(e);
			throw new RuntimeException(e);
		}
		keyPairGenerator.initialize(256);//最大 571 bits.
        //KeyPair keyPair = keyPairGenerator.generateKeyPair();
        return keyPairGenerator.generateKeyPair();
//        RSAPublicKey rsaPublicKey = (RSAPublicKey) keyPair.getPublic();
//        RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) keyPair.getPrivate();
//        pk =  rsaPublicKey.getEncoded();
//        sk = rsaPrivateKey.getEncoded();
        //System.out.println("RSA公钥：" + parseByte2HexStr(pk));
        //System.out.println("RSA私钥：" + parseByte2HexStr(sk));//可以将其保存到本地文件中
 //       return new byte[][] {keyPair.getPublic().getEncoded(),keyPair.getPrivate().getEncoded()};
 	}
	


	
	@Override
	public PublicKey getKey() {
		try {
			return RsaClient.publicKey(pk);
		} catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
			if(Pblog.INIT)Pblog.INIT(e);
			throw new RuntimeException(e);
		}
	}
	@Override
	public PrivateKey keyPrivate() {
		if(Pblog.SECURE) {
			StackTraceElement stet = null;{
				for (StackTraceElement ste : Thread.currentThread().getStackTrace()) {
					if(!Thread.class.getName().equals(ste.getClassName()) && !EcServer.class.getName().equals(ste.getClassName()) && ste.getFileName()!=null && ste.getLineNumber()>=0) {
						stet = ste;
						break;
					}
				}
			}
			Pblog.SECURE("get EC privateKey from ",stet);
		}
		return sk;
	}
	
	/**
	 * 通过应原来大小，返回加密后大小;
	 */
	public int outputLength(int inputLength) {
		return encode.getOutputSize(inputLength);
	}
	public int encode(ByteBuffer one) throws ShortBufferException, IllegalBlockSizeException, BadPaddingException {
		int s = encode.doFinal(one.array(), one.position()+one.arrayOffset(), one.remaining(), one.array(), one.position()+one.arrayOffset());
		one.limit(one.position()+s);
		return s;
	}
	public int encode(ByteBuffer input,ByteBuffer output) throws ShortBufferException, IllegalBlockSizeException, BadPaddingException {
		return encode.doFinal(input, output);
	}
	
	
	/**
	 * 必须要等于大于 ，并且为此数的倍数才能开始解压;
	 */
	public int blockSize() {
		return decode.getBlockSize();
	}
	public int decode(ByteBuffer one) throws ShortBufferException, IllegalBlockSizeException, BadPaddingException {
		int s = decode.doFinal(one.array(), one.position()+one.arrayOffset(), one.remaining(), one.array(), one.position()+one.arrayOffset());
		one.limit(one.position()+s);
		return s;
	}
	public int decode(ByteBuffer input,ByteBuffer output) throws ShortBufferException, IllegalBlockSizeException, BadPaddingException {
		return decode.doFinal(input, output);
	}
	
	public byte[] sign(ByteBuffer bb) throws SignatureException {
	     signature.update(bb);
	     return signature.sign();
	     //byte[] result = signature.sign();
	     //System.out.println("RSA签名：" + parseByte2HexStr(result));
	}
	
}
